using Client.Framework;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

public class FindReferenceMiss
{
    static FindReferenceMiss findRefMiss = new FindReferenceMiss();

    [MenuItem("GameObject/Tools/FindReferenceMiss")]
    public static void FindGoReferenceMiss()
    {
        var selectObjs = Selection.gameObjects;
        for (int i = 0; i < selectObjs.Length; i++)
        {
            var assetPath = AssetDatabase.GetAssetPath(selectObjs[i]);
            findRefMiss.FindReferenceLose(selectObjs[i]);
            EditorUtility.DisplayProgressBar("查找资源引用丢失", assetPath, (i + 1f) / selectObjs.Length);
        }
        EditorUtility.ClearProgressBar();
    }

    [MenuItem("Tools/FindReferenceMiss")]
    public static void FindAssetReferenceMiss()
    {
        var assetGuids = AssetDatabase.FindAssets("t:Prefab");
        for (int i = 0; i < assetGuids.Length; i++)
        {
            var assetPath = AssetDatabase.GUIDToAssetPath(assetGuids[i]);
            var obj = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);

            if (obj != null) { findRefMiss.FindReferenceLose(obj); }
            EditorUtility.DisplayProgressBar("查找资源引用丢失", assetPath, (i + 1f) / assetGuids.Length);
        }

        Debug.Log($"总共查找到:{assetGuids.Length}个资源预设");
        EditorUtility.ClearProgressBar();
    }

    [MenuItem("GameObject/Tools/CheckScriptMiss")]
    public static void CheckGoScriptMiss()
    {
        var selectObjs = Selection.gameObjects;
        for (int i = 0; i < selectObjs.Length; i++)
        {
            var path = AssetDatabase.GetAssetPath(selectObjs[i]);
            if (GameObjectUtility.RemoveMonoBehavioursWithMissingScript(selectObjs[i]) > 0)
            {
                Debug.LogWarning($"组件丢失:", selectObjs[i]);
                EditorUtility.SetDirty(selectObjs[i]);
            }
            EditorUtility.DisplayProgressBar("查找资源脚本丢失", path, (i + 1f) / selectObjs.Length);
        }
        EditorUtility.ClearProgressBar();
    }

    [MenuItem("Tools/CheckScriptMiss")]
    public static void CheckAssetScriptMiss()
    {
        var assetGuids = AssetDatabase.FindAssets("t:Prefab");
        for (int i = 0; i < assetGuids.Length; i++)
        {
            var assetPath = AssetDatabase.GUIDToAssetPath(assetGuids[i]);
            var obj = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);

            if (obj != null) { RemoveScriptMiss(obj); }
            EditorUtility.DisplayProgressBar("查找资源脚本丢失", assetPath, (i + 1f) / assetGuids.Length);
        }

        Debug.Log($"总共查找到:{assetGuids.Length}个资源预设");
        EditorUtility.ClearProgressBar();
    }

    public void FindReferenceLose(GameObject obj)
    {
        var childNodes = new List<GameObject>() { obj };
        FindChildNodes(obj.transform, childNodes);

        foreach (var node in childNodes)
        {
            var components = node.GetComponents<Component>();
            string path = node.transform.BuildTfPath();

            foreach (var component in components)
            {
                if (component == null)
                {
                    Debug.LogWarning($"组件丢失:{path}", obj);
                    continue;
                }

                if (IsMissReference(component))
                {
                    string typeName = component.GetTypeName();
                    Debug.LogWarning($"资源引用丢失:{path}\n组件类型{typeName}", obj);
                }
            }
        }
    }

    public static void RemoveScriptMiss(GameObject go)
    {
        bool found = false; var serialize = new SerializedObject(go);
        var property = serialize.FindProperty("m_Component");
        var components = go.GetComponents<Component>();

        for (var j = components.Length - 1; j >= 0; j--)
        {
            if (components[j] == null)
            {
                found = true;
                property.DeleteArrayElementAtIndex(j);
            }
        }

        if (found)
        {
            serialize.ApplyModifiedProperties();
            string path = go.transform.BuildTfPath();
            Debug.LogWarning($"组件丢失:{path}", go);
        }
    }

    void FindChildNodes(Transform tf, List<GameObject> nodes)
    {
        for (int i = 0; i < tf.childCount; i++)
        {
            var child = tf.GetChild(i);
            nodes.Add(child.gameObject);
            FindChildNodes(child, nodes);
        }
    }

    bool IsMissReference(Component component)
    {
        if (component is Transform) { return false; }
        var serialized = new SerializedObject(component);
        var property = serialized.GetIterator();

        while (property.NextVisible(true))
        {
            if (property.propertyType == SerializedPropertyType.ObjectReference)
            {
                if (property.objectReferenceValue == null &&
                    property.objectReferenceInstanceIDValue != 0)
                {
                    Debug.LogWarning($"属性名{property.displayName}");
                    return true;
                }
            }
        }
        return false;
    }
}